package cn.wolfcode.business.service.impl;

import java.io.IOException;
import java.io.InputStream;
import java.util.Collections;
import java.util.List;

import cn.wolfcode.business.vo.DeployVO;
import cn.wolfcode.common.exception.ServiceException;
import cn.wolfcode.common.utils.file.FileUploadUtils;
import lombok.SneakyThrows;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.image.impl.DefaultProcessDiagramGenerator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import cn.wolfcode.business.mapper.BpmnInfoMapper;
import cn.wolfcode.business.domain.BpmnInfo;
import cn.wolfcode.business.service.IBpmnInfoService;
import org.springframework.web.multipart.MultipartFile;

/**
 * 流程定义明细Service业务层处理
 * 
 * @author dafei
 * @date 2023-11-01
 */
@Service
public class BpmnInfoServiceImpl implements IBpmnInfoService 
{
    @Autowired
    private BpmnInfoMapper bpmnInfoMapper;

    @Autowired
    private RepositoryService repositoryService;

    /**
     * 查询流程定义明细
     * 
     * @param id 流程定义明细主键
     * @return 流程定义明细
     */
    @Override
    public BpmnInfo selectBpmnInfoById(Long id)
    {
        return bpmnInfoMapper.selectBpmnInfoById(id);
    }

    /**
     * 查询流程定义明细列表
     * 
     * @param bpmnInfo 流程定义明细
     * @return 流程定义明细
     */
    @Override
    public List<BpmnInfo> selectBpmnInfoList(BpmnInfo bpmnInfo)
    {
        return bpmnInfoMapper.selectBpmnInfoList(bpmnInfo);
    }

    /**
     * 新增流程定义明细
     * 
     * @param bpmnInfo 流程定义明细
     * @return 结果
     */
    @Override
    public int insertBpmnInfo(BpmnInfo bpmnInfo)
    {
        return bpmnInfoMapper.insertBpmnInfo(bpmnInfo);
    }

    /**
     * 修改流程定义明细
     * 
     * @param bpmnInfo 流程定义明细
     * @return 结果
     */
    @Override
    public int updateBpmnInfo(BpmnInfo bpmnInfo)
    {
        return bpmnInfoMapper.updateBpmnInfo(bpmnInfo);
    }

    /**
     * 批量删除流程定义明细
     * 
     * @param ids 需要删除的流程定义明细主键
     * @return 结果
     */
    @Override
    public int deleteBpmnInfoByIds(Long[] ids)
    {
        Long id = ids[0];
        //需要删除啥?
        BpmnInfo bpmnInfo = bpmnInfoMapper.selectBpmnInfoById(id);
        if(bpmnInfo == null){
            throw new ServiceException("参数异常");
        }
        //流程已经部署了, 需要直接删除部署信息
        //有没有可能流程已经启动了呢?---直接删除即可
        //流程图只允许一份, 这么写是没有问题, 如果是多份
       /* Deployment deployment = repositoryService.createDeploymentQuery()
                .processDefinitionKey(bpmnInfo.getProcessDefinitionKey())
                .singleResult();*/
        //多份
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                .processDefinitionKey(bpmnInfo.getProcessDefinitionKey())
                .processDefinitionVersion(bpmnInfo.getVersion())
                .singleResult();

        if(processDefinition != null){
            repositoryService.deleteDeployment(processDefinition.getDeploymentId(), true);
        }
        //@TODO 流程启动之后, 会改动业务数据状态, 此时需要额外重置
        // ServiceItem--- CarPackageAudit ---- 审核撤销/初始化/待审核
        //BpmnInfo 要删除
        return bpmnInfoMapper.deleteBpmnInfoById(id);
    }

    /**
     * 删除流程定义明细信息
     * 
     * @param id 流程定义明细主键
     * @return 结果
     */
    @Override
    public int deleteBpmnInfoById(Long id)
    {
        return bpmnInfoMapper.deleteBpmnInfoById(id);
    }

    @Override
    public void deploy(DeployVO vo) throws IOException {
        //参数判断--文件大小--文件后缀
        if(vo == null){
            throw new ServiceException("参数异常");
        }
        MultipartFile file = vo.getFile();
        if(file == null || file.getSize() == 0){
            throw new ServiceException("必需选择一个流程文件");
        }
        String ext = FileUploadUtils.getExtension(file);
        if(!"bpmn".equalsIgnoreCase(ext)){
            throw new ServiceException("文件格式必须为 bpmn 格式");
        }
        //流程部署
        Deployment deployment = repositoryService.createDeployment()
                .addInputStream(vo.getBpmnLabel(), file.getInputStream())
                .deploy();
        //流程类-解下流程文件, 获取流程文件所有信息封装对象-ProcessDefinition---act_re_procdef
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                .deploymentId(deployment.getId()).singleResult();
        //保存流程信息对象: BpmnInfo
        BpmnInfo bpmnInfo = new BpmnInfo();
        bpmnInfo.setInfo(vo.getInfo());
        bpmnInfo.setBpmnLabel(vo.getBpmnLabel());
        bpmnInfo.setBpmnType(vo.getBpmnType());

        bpmnInfo.setDeployTime(deployment.getDeploymentTime());
        bpmnInfo.setVersion(processDefinition.getVersion());
        bpmnInfo.setProcessDefinitionKey(processDefinition.getKey());

        bpmnInfoMapper.insertBpmnInfo(bpmnInfo);

    }

    @Override
    public InputStream getResource(Long id, String type) {
        //参数判断
        BpmnInfo bpmnInfo = bpmnInfoMapper.selectBpmnInfoById(id);
        if(bpmnInfo == null  || !("xml".equalsIgnoreCase(type) || "png".equalsIgnoreCase(type))){
            throw new ServiceException("参数异常");
        }
        //怎么获取资源??
        InputStream inputStream = null;
        //建议流程部署尽量只有1份
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                .processDefinitionKey(bpmnInfo.getProcessDefinitionKey())
                .processDefinitionVersion(bpmnInfo.getVersion())  //指定版本
                .singleResult();//???
        if("xml".equalsIgnoreCase(type)){
            inputStream = repositoryService.getResourceAsStream(processDefinition.getDeploymentId(), bpmnInfo.getBpmnLabel());
        }else if("png".equalsIgnoreCase(type)){
            //图片
            DefaultProcessDiagramGenerator processDiagramGenerator = new DefaultProcessDiagramGenerator();
            BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinition.getId());
            /**
             * 第一个参数: 流程定义模型
             * 第二个参数: 高亮节点集合
             * 第三个参数: 高亮连线集合
             */
            inputStream = processDiagramGenerator.generateDiagram(bpmnModel,
                    Collections.emptyList(),
                    Collections.emptyList(),
                    "宋体",
                    "宋体",
                    "宋体");
        }
        return inputStream;
    }
}
